#ifndef VSMaterial_H
#define VSMaterial_H
#include "VSObject.h"
#include "VSShaderMainFunction.h"
#include "VSTexAllState.h"
#include "VSLight.h"
#include "VSResource.h"
#include "VSMaterialPass.h"
#include "VSNormalDepthPass.h"
#include "VSShaderKey.h"
#include "VSRenderState.h"
#include "VSPass.h"
namespace VSEngine2
{
	class VSStream;
	class VSGRAPHIC_API MaterialCustomPara
	{
	public:
		MaterialCustomPara()
		{

		}
		~MaterialCustomPara()
		{

		}
		VSUsedName ConstValueName;
		unsigned int DiskUse()const
		{
			unsigned int uiUsed = 0;
			uiUsed += ConstValueName.DiskUse();
			return uiUsed;
		}
		bool Save(VSStream & rStream,unsigned int &iSaveUse)const;

		bool Load(VSStream & rStream,unsigned int &iSaveUse);

		MaterialCustomPara & operator =(const MaterialCustomPara &Para)
		{
			ConstValueName = Para.ConstValueName;
			return *this;
		}
		VSGRAPHIC_API friend bool operator >(const MaterialCustomPara &Para1,const MaterialCustomPara &Para2)
		{
			return Para2.ConstValueName > Para1.ConstValueName;
		}
		VSGRAPHIC_API friend bool operator <(const MaterialCustomPara &Para1,const MaterialCustomPara &Para2)
		{
			return Para2.ConstValueName < Para1.ConstValueName;
		}
		VSGRAPHIC_API friend bool operator ==(const MaterialCustomPara &Para1,const MaterialCustomPara &Para2)
		{
			return Para2.ConstValueName == Para1.ConstValueName;
		}
	};
	class VSGRAPHIC_API CustomFloatValue : public MaterialCustomPara
	{
	public:
		CustomFloatValue()
		{

		}
		~CustomFloatValue()
		{

		}
		VSArray<VSREAL> Value;
		CustomFloatValue & operator =(const CustomFloatValue &Para)
		{
			MaterialCustomPara::operator =(Para);
			Value = Para.Value;
			return *this;
		}
		unsigned int DiskUse()const
		{
			unsigned int uiUsed = 0;
			uiUsed += sizeof(unsigned int);
			uiUsed += Value.GetNum() * sizeof(VSREAL);
			return uiUsed;
		}
		bool Save(VSStream & rStream,unsigned int &iSaveUse)const;
		
		bool Load(VSStream & rStream,unsigned int &iSaveUse);
		
	};
	class CustomTexSampler : public MaterialCustomPara
	{
	public:
		CustomTexSampler()
		{
			m_pTexture = NULL;
		}
		~CustomTexSampler()
		{
			m_pTexture = NULL;
		}
		VSTexAllStateRPtr m_pTexture;
		CustomTexSampler & operator =(const CustomTexSampler &Para)
		{
			MaterialCustomPara::operator =(Para);
			m_pTexture = Para.m_pTexture;
			return *this;
		}
		unsigned int DiskUse()const;

		bool Save(VSStream & rStream,unsigned int &iSaveUse)const;

		bool Load(VSStream & rStream,unsigned int &iSaveUse);
	
		bool Link(VSStream & rStream)
		{

			return 1;
		}
		bool Register(VSStream & rStream)const
		{
			return 1;
		}
	};
	class VSGRAPHIC_API VSMaterialInterface : public VSObject , public VSResource
	{
		//RTTI
		DECLARE_RTTI;
		DECLARE_INITIAL_NO_CLASS_FACTORY;
	public:
		
		VSMaterialInterface();
		virtual ~VSMaterialInterface() = 0;
		

		
	public:

		virtual unsigned int DiskUse()const;

		virtual bool Save(VSStream & rStream,unsigned int &iSaveUse)const;
		virtual bool Load(VSStream & rStream,unsigned int &iSaveUse);
		virtual bool Register(VSStream & rStream)const;
		virtual bool Link(VSStream & rStream);
	public:
		virtual bool Clone(const VSObject *pObject,unsigned int uiType);


		virtual unsigned int GetResourceType()const
		{
			return RT_MATERIAL;
		}
		
	};
	DECLARE_Ptr(VSMaterialInterface);
	VSTYPE_MARCO(VSMaterialInterface);
	class VSGRAPHIC_API VSCustomMaterial : public VSMaterialInterface
	{
		//RTTI
		DECLARE_RTTI;
		//PRIORITY
		
	public:
		VSCustomMaterial(const VSUsedName & ResourceName,
						const TCHAR * pVShaderFileName,const TCHAR * pVMainFunName,
						const TCHAR * pPShaderFileName,const TCHAR * pPMainFunName,
						VSShaderKey * pVShaderKey = NULL,VSShaderKey * pPShaderKey = NULL);
		virtual ~VSCustomMaterial();
		bool UseMaterial();
		void PreLoad(const VSUsedName & ResourceName,
			const TCHAR * pVShaderFileName,const TCHAR * pVMainFunName,
			const TCHAR * pPShaderFileName,const TCHAR * pPMainFunName,
			VSShaderKey * pVShaderKey = NULL,VSShaderKey * pPShaderKey = NULL);
		friend class VSRenderer;
		static VSCustomMaterial * GetPostGray()
		{
			return ms_pPostGray;
		}
		static VSCustomMaterial * GetPostScreenQuad()
		{
			return ms_pPostScreenQuad;
		}
		virtual void SetVShaderValue(const VSUsedName & Name,VSREAL *fValue,unsigned int uiSize);

		virtual void SetVShaderTexture(const VSUsedName & TexSamplerNodeName,VSTexAllState * pTex);

		virtual void SetPShaderValue(const VSUsedName & Name,VSREAL *fValue,unsigned int uiSize);

		virtual void SetPShaderTexture(const VSUsedName & TexSamplerNodeName,VSTexAllState * pTex);
		VSRenderState & GetRenderState();
		void SetBlendState(VSBlendState * pBlendState);
		void SetDepthStencilState(VSDepthStencilState *pDepthStencilState);
		void SetRasterizerState(VSRasterizerState *pRasterizerState);
		void AddClipPlane(const VSPlane3 & Plane);
		void AddScissorRect(const VSRect2 & Rect);
	protected:
		VSCustomMaterial();
		VSVShaderPtr m_pVShader;
		VSPShaderPtr m_pPShader;
		VSRenderState	m_RenderState;
		bool LoadFromCache(const VSUsedName & Name,VSShaderKey * pVShaderKey = NULL,VSShaderKey * pPShaderKey = NULL);
	public:
		static bool RegisterMainFactory();
	private:
		static bool InitialClassFactory();	
		static VSObject * FactoryFunc();
		static bool ms_bRegisterMainFactory;
		static bool InitialDefaultState();
		static bool TerminalDefaultState();
	protected:
		static VSPointer<VSCustomMaterial> ms_pPostGray;
		static VSPointer<VSCustomMaterial> ms_pPostScreenQuad;
		static bool LoadDefault();
// 	public:
// 		virtual bool Load(VSStream & rStream,unsigned int &iSaveUse);
// 		virtual bool Register(VSStream & rStream)const;
// 		virtual bool Clone(const VSObject *pObject,unsigned int uiType);
	};
	typedef VSPointer<VSCustomMaterial> VSCustomMaterialPtr;
	class VSGRAPHIC_API VSMaterialBase : public VSMaterialInterface
	{
		//RTTI
		DECLARE_RTTI;

		DECLARE_INITIAL_NO_CLASS_FACTORY;
	public:
		
		VSMaterialBase();
		virtual ~VSMaterialBase();

	protected:
		VSArrayOrder<CustomFloatValue> m_VShaderCustomValue;
		VSArrayOrder<CustomTexSampler>m_VShaderCustomTex;

		VSArrayOrder<CustomFloatValue> m_PShaderCustomValue;
		VSArrayOrder<CustomTexSampler>m_PShaderCustomTex;
	public:

		virtual unsigned int DiskUse()const;

		virtual bool Save(VSStream & rStream,unsigned int &iSaveUse)const;
		virtual bool Load(VSStream & rStream,unsigned int &iSaveUse);

	public:
		virtual bool Clone(const VSObject *pObject,unsigned int uiType);


		virtual void SetVShaderValue(const VSUsedName & Name,VSREAL *fValue,unsigned int uiSize);

		virtual void SetVShaderTexture(const VSUsedName & TexSamplerNodeName,VSTexAllStateR * pTex);

		virtual void SetPShaderValue(const VSUsedName & Name,VSREAL *fValue,unsigned int uiSize);

		virtual void SetPShaderTexture(const VSUsedName & TexSamplerNodeName,VSTexAllStateR * pTex);

	};
	DECLARE_Ptr(VSMaterialBase);
	VSTYPE_MARCO(VSMaterialBase);
	class VSGRAPHIC_API VSMaterial : public VSMaterialBase
	{
		//RTTI
		DECLARE_RTTI;
		//PRIORITY
		
		DECLARE_INITIAL
	protected:
		VSMaterial();
		VSUsedName m_ShowName;
		VSArray<VSShaderMainFunction*> m_pShaderMainFunction;
		VSArray<VSShaderFunction *> m_pShaderFunctionArray;
		
		

		bool m_bIsAllReadyLink;
		
		VSPassPtr m_pPass[VSPass::PT_MAX];
		bool m_bIsCombine;
	public:
		void SetBlendState(VSBlendState * pBlendState,unsigned int uiPassId = 0);
		void SetDepthStencilState(VSDepthStencilState *pDepthStencilState,unsigned int uiPassId = 0);
		void SetRasterizerState(VSRasterizerState *pRasterizerState,unsigned int uiPassId = 0);
		void AddClipPlane(const VSPlane3 & Plane,unsigned int uiPassId = 0);
		void AddScissorRect(const VSRect2 & Rect,unsigned int uiPassId = 0);
		void AddPass(unsigned int uiSMType);
		inline VSRenderState & GetRenderState(unsigned int uiPassId)
		{
			return m_pShaderMainFunction[uiPassId]->GetRenderState();
		}
		inline void SetCombine(bool IsCombine)
		{
			m_bIsCombine = IsCombine;
		}
		inline bool GetCombine()const
		{
			return m_bIsCombine;
		}
		friend class VSRenderer;
		friend class VSMaterialInstance;
		VSMaterial(const VSUsedName &ShowName,unsigned int uiSMType = VSShaderMainFunction::SM_PHONE);
		virtual ~VSMaterial();
		inline VSMaterialPass * GetMaterialPass()const
		{
			VSPass * pPass = m_pPass[VSPass::PT_MATERIAL];
			return (VSMaterialPass *)pPass;
		}
		inline VSNormalDepthPass * GetNormalDepthPass()const
		{
			VSPass * pPass = m_pPass[VSPass::PT_NORMALDEPTH];
			return (VSNormalDepthPass *)pPass;
		}
		void AddShaderFuntion(VSShaderFunction *pShaderFuntion);
		void DeleteShaderFuntion(VSShaderFunction *pShaderFuntion);
		inline VSShaderMainFunction * GetShaderMainFunction(unsigned char uPassId = 0)const
		{
			return m_pShaderMainFunction[uPassId];
		}
		unsigned int GetShaderMainFunctionNum()const
		{
			return m_pShaderMainFunction.GetNum();
		}
		inline const VSUsedName & GetShowName()const
		{
			return m_ShowName;
		}
		inline bool IsAllReadyLink()const
		{
			return m_bIsAllReadyLink;
		}

		void LinkAllResource();
		void ClearShaderFuntionVisitFlagFalse();
		inline bool GetShaderTreeString(VSString & OutString,VSArray<VSLightPtr> &LightArray,unsigned int uiOST,unsigned char uPassId = 0)
		{
			m_pShaderMainFunction[uPassId]->SetLight(LightArray);
			m_pShaderMainFunction[uPassId]->ClearShaderTreeStringFlag();
			return m_pShaderMainFunction[uPassId]->GetShaderTreeString(OutString,uiOST);
		}
		void CreateCustomValue(VSPShader * pShader);

		void CreateConstValueDeclare(VSString & OutString,unsigned int uiRegisterID);

		void CreateCustomTexture(VSPShader * pShader);
		void CreateTextureDeclare(VSString & OutString,unsigned int uiRegisterID);

	
		
	public:
		static bool InitialDefaultState();
		static bool TerminalDefaultState();
	public:
		
		virtual unsigned int DiskUse()const;

		virtual bool Save(VSStream & rStream,unsigned int &iSaveUse)const;
		virtual bool Load(VSStream & rStream,unsigned int &iSaveUse);
		virtual bool Register(VSStream & rStream)const;
		virtual bool Link(VSStream & rStream);
		virtual bool PostLoad(void * pDate = NULL);
		//Clone
	public:
		virtual bool Clone(const VSObject *pObject,unsigned int uiType);
		virtual bool PostClone(VSObject * pObjectSrc);
	protected:
		static VSPointer<VSMaterial> Default;
		static VSPointer<VSMaterial> DefaultOnlyColor;
		static VSPointer<VSMaterial> DefaultOnlyVertexColor;

		static VSPointer<VSMaterial> DefaultOnlyColorDisableDepth;
		static VSPointer<VSMaterial> DefaultOnlyVertexColorDisableDepth;
		static bool LoadDefault();
	public:
		static bool ms_bIsEnableASYNLoader;
		static bool ms_bIsEnableGC;
		friend class VSRenderer;
		static const VSMaterial *GetDefalut()
		{
			return Default;
		}
		
		static const VSMaterial *GetDefaultOnlyColor()
		{
			return DefaultOnlyColor;
		}
		
		static const VSMaterial *GetDefaultOnlyVertexColor()
		{
			return DefaultOnlyVertexColor;
		}
		
		static const VSMaterial *GetDefaultOnlyColorDisableDepth()
		{
			return DefaultOnlyColorDisableDepth;
		}

		static const VSMaterial *GetDefaultOnlyVertexColorDisableDepth()
		{
			return DefaultOnlyVertexColorDisableDepth;
		}
	};
	DECLARE_Ptr(VSMaterial);
	DECLARE_Proxy(VSMaterial);
	VSTYPE_MARCO(VSMaterial);

	class VSGRAPHIC_API VSMaterialInstance: public VSObject
	{
		//RTTI
		DECLARE_RTTI;

		DECLARE_INITIAL
		
	public:
		VSMaterialInstance(VSMaterialR * pMaterial);
		virtual ~VSMaterialInstance();
	protected:
		VSMaterialInstance();
		VSArrayOrder<CustomFloatValue> m_VShaderCustomValue;
		VSArrayOrder<CustomFloatValue> m_PShaderCustomValue;
		VSArrayOrder<CustomTexSampler>	m_VShaderCustomTex;		
		VSArrayOrder<CustomTexSampler>	m_PShaderCustomTex;		


		VSVShaderPtr m_pCurVShader[VSPass::PT_MAX];
		VSPShaderPtr m_pCurPShader[VSPass::PT_MAX];
		VSMaterialRPtr m_pMaterial;

	public:
		friend class VSSpatial;

		void SetPShaderValue(VSPShader * pPShader);
		void SetVShaderValue(VSVShader * pVShader);
		void SetVShaderValue(const VSUsedName & Name,VSREAL *fValue,unsigned int uiSize);
		void DeleteVShaderValue(const VSUsedName &Name);

		void SetVShaderTexture(const VSUsedName & TexSamplerNodeName,VSTexAllStateR * pTex);
		void DeleteVShaderTexture(const VSUsedName & TexSamplerNodeName);

		void SetPShaderValue(const VSUsedName & Name,VSREAL *fValue,unsigned int uiSize);
		void DeletePShaderValue(const VSUsedName &Name);

		void SetPShaderTexture(const VSUsedName & TexSamplerNodeName,VSTexAllStateR * pTex);
		void DeletePShaderTexture(const VSUsedName & TexSamplerNodeName);

		void GetAllMaterialPara();

		inline VSMaterial* GetMaterial()const
		{
			return m_pMaterial->GetResource();
		}
		inline VSMaterialR * GetMaterialR()const
		{
			return m_pMaterial;
		}
		friend class VSMaterialPass;
		friend class VSNormalDepthPass;
		friend class VSPrezPass;
	public:

		virtual unsigned int DiskUse()const;

		virtual bool Save(VSStream & rStream,unsigned int &iSaveUse)const;
		virtual bool Load(VSStream & rStream,unsigned int &iSaveUse);
		virtual bool Register(VSStream & rStream)const;
		virtual bool Link(VSStream & rStream);
		//Clone
	public:
		virtual bool Clone(const VSObject *pObject,unsigned int uiType);
	};
	DECLARE_Ptr(VSMaterialInstance);
	VSTYPE_MARCO(VSMaterialInstance);
	typedef VSPointer<VSMaterialInstance> VSMaterialInstancePtr;
	class VSGRAPHIC_API VSMaterialOnlyTexture : public VSMaterial
	{
	protected:
		VSMaterialOnlyTexture();
	public:
		VSMaterialOnlyTexture(const VSUsedName &ShowName,VSTexAllStateR * pTexture);
		virtual ~VSMaterialOnlyTexture();
		
	};
	typedef VSPointer<VSMaterialOnlyTexture> VSMaterialOnlyTexturePtr;
	class VSGRAPHIC_API VSMaterialTextureAndNormal : public VSMaterial
	{
	protected:
		VSMaterialTextureAndNormal();
	public:
		VSMaterialTextureAndNormal(const VSUsedName &ShowName,VSTexAllStateR * pDiffuseTexture,VSTexAllStateR * pNormalTexture);
		virtual ~VSMaterialTextureAndNormal();
	};
	typedef VSPointer<VSMaterialTextureAndNormal> VSMaterialTextureAndNormalPtr;

	class VSGRAPHIC_API VSMaterialOnlyEmissive : public VSMaterial
	{
	protected:
		VSMaterialOnlyEmissive();
	public:
		VSMaterialOnlyEmissive(const VSUsedName &ShowName);
		virtual ~VSMaterialOnlyEmissive();

	};
	typedef VSPointer<VSMaterialOnlyEmissive> VSMaterialOnlyEmissivePtr;

	class VSGRAPHIC_API VSMaterialDNSE : public VSMaterial
	{
	protected:
		VSMaterialDNSE();
	public:
		VSMaterialDNSE(const VSUsedName &ShowName,VSTexAllStateR * pDiffuseTexture,VSTexAllStateR * pNormalTexture,
			VSTexAllStateR * pSpecularTexture, VSTexAllStateR * pEmissiveTexture);
		virtual ~VSMaterialDNSE();

	};
	typedef VSPointer<VSMaterialDNSE> VSMaterialDNSEPtr;
}
#endif